<?php
/**
 * Copyright (C) 2013 Pablo Sepúlveda P. <psep.pentauc@gmail.com>
 * 
 * This file is part of gAbstract.
 * WarpIT is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 * 
 * gAbstract is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with gAbstract.  If not, see <http://www.gnu.org/licenses/>.
 */
 
require_once 'LoadLibs.php';

/**
 * Clase que genera las Entidades.
 * 
 * @author psep
 * @version 1.0
 * @package gAbstract
 * @copyright Copyright (c) 2013 Pablo Sepúlveda P.
 * @license GNU GPLv3 or later
 * @link http://www.psep.cl
 */
class GenerateEntities extends ExecuteBean{
	
	/**
	 * Objeto string estático que carga la ruta
	 * del template de inicio de las entidades.
	 * 
	 * @var static String
	 */
	private static $START_CLASS = "example/_baseClass_.txt";
	
	/**
	 * Objeto string estático que carga la ruta
	 * del template del final de las entidades.
	 * 
	 * @var static String
	 */
	private static $END_CLASS 	= "example/_endClass_.txt";
	
	/**
	 * Objeto string estático que carga el nombre por
	 * defecto de la entidad template que será reemplazada.
	 * 
	 * @var static String
	 */
	private static $CLASSNAME	= "_ClassName_";
	
	/**
	 * Objeto string estático que carga el nombre del getter
	 * 
	 * @var static String
	 */
	private static $GETTER		= "get";
	
	/**
	 * Objeto string estático que carga el nombre del setter
	 * 
	 * @var static String
	 */
	private static $SETTER		= "set";
	
	/**
	 * fopen Option Write file (w).
	 * 
	 * @var string
	 */
	protected static $fopenWrite = "w";
	
	/**
	 * fopen Option read file (r).
	 * 
	 * @var string
	 */
	protected static $fopenRead	= "r";
	
	/**
	 * fopen option Open for writing only, 
	 * place the file pointer at the end of the file (a).
	 * 
	 * @var string
	 */
	protected static $fopenWritePointerEnd = "a";
	
	/**
	 * Nombre de la carpeta donde serán almacenadas
	 * las entidades.
	 * 
	 * @var string
	 */
	private $folderEntities;
	
	/**
	 * Constructor de la clase.
	 * 
	 * @param Integer $dbType tipo de db
	 * @param String $dbHost
	 * @param String $dbPort
	 * @param String $dbName 
	 * @param String $dbUser
	 * @param String $dbPass
	 * @param String $folder carpeta de Entidades
	 */
	function __construct() {
		$this->folderEntities = FOLDER_ENTITIES;
	}
	
	/**
	 * Método de inicio a la generación de Entidades.
	 */
	public function start() {
		$tables = $this->mapping();
		
		if(count($tables) == 0){
			throw new Exception("Error: La base de datos no contiene tablas o existen problemas de permisos, verifique", 1);
		}else if(!file_exists($this->folderEntities)){
			throw new Exception("Error: La carpeta ".$this->folderEntities." para Entidades no existe, verifique", 1);
		}else{
			echo "Entities folder -> ".$this->folderEntities."\n\n";
			
			$iter = new IteratorPattern($tables);
			
			while($iter->hasNext()){
				$tabla	= (String) $iter->next()->TABLE_NAME;
				$campos = $this->mapping($tabla);
				echo "Tabla -> ".$tabla."\n";
				$this->generateClass($tabla, $campos);
				echo "\n\n";
			}
			
			echo "\nEntidades generadas!\n\n";
		}
	}
	
	/**
	 * Método que genera Clases Entidades
	 * a partir de templates.
	 * 
	 * @param String $tableName
	 * @param array $fields
	 */
	private function generateClass($tableName, $fields){
		$className		= NameUtils::formalName($tableName);
		$fileStartClass = file(static::$START_CLASS);
		$fileEntity		= fopen($this->folderEntities."/".$className.".php", static::$fopenWrite);
		
		foreach ($fileStartClass as $key => $line) {
			$newLine = str_replace(static::$CLASSNAME, $className, $line);
			fwrite($fileEntity, $newLine);
		}
		
		$iter = new IteratorPattern($fields);

		while($iter->hasNext()){
			$obj   = $iter->next();
			fwrite($fileEntity, "\t/** ".$this->getCommentAttribute($obj)." */\n");
			fwrite($fileEntity, $this->generateField(2, $obj->COLUMN_NAME));
		}
		
		fwrite($fileEntity, "\n\n");
		
		$iter = new IteratorPattern($fields);
		
		while($iter->hasNext()){
			$obj   = $iter->next();
			$campo = $obj->COLUMN_NAME;
			$object= NameUtils::formalObjectName($campo);
			$formal= NameUtils::formalName($campo);
			$docu  = $this->getCommentAttribute($obj);
			$cast  = NameUtils::castName($obj->DATA_TYPE);
			// Generate Getter
			fwrite($fileEntity, "\t/** ".$docu." */\n");
			fwrite($fileEntity, "\tpublic function ".static::$GETTER.$formal."(){\n");
			fwrite($fileEntity, "\t\treturn ".$cast."\$this->".$object.";\n");
			fwrite($fileEntity, "\t}\n\n");
			// Generate Setter
			fwrite($fileEntity, "\t/** ".$docu." */\n");
			fwrite($fileEntity, "\tpublic function ".static::$SETTER.$formal."(\$".$object."){\n");
			fwrite($fileEntity, "\t\t\$this->".$object." = ".$cast."\$".$object.";\n");
			fwrite($fileEntity, "\t}\n\n");
		}
		
		$fileEndClass	= file(static::$END_CLASS);
		
		foreach ($fileEndClass as $key => $line) {
			fwrite($fileEntity, $line);
		}
		
		fclose($fileEntity);

	}

	/**
	 * Método que recibe el resultSet en un objeto
	 * de tipo stdClass para retornar la documentación
	 * de los atributos de la entidad.
	 * 
	 * @param stdClass Object
	 * @return String
	 */
	private function getCommentAttribute($rs){
		$isNull	= $this->getBoolColumn($rs->IS_NULLABLE);
		$type	= ObjectUtil::getTypeDB($rs->DATA_TYPE, 1);
		$max	= $rs->MAXLENGTH;
		$key	= $rs->COLUMN_KEY;
		
		$glosa	= new StringBuilder();
		$glosa->append("@Column(name=\"");
		$glosa->append($rs->COLUMN_NAME);
		$glosa->append("\", type=\"");
		$glosa->append($type);
		
		if($max != null && trim($max) != ""){
			$glosa->append("\", length=\"");
			$glosa->append($max);
		}
		
		if($key != null && trim($key) != ""){
			$glosa->append("\", key=\"");
			$glosa->append($key);
		}
		
		$glosa->append("\")");
		
		echo $glosa->toString()."\n";
		
		return $glosa->toString();
	}
	
	/**
	 * Método que recibe parámetro de columna formal
	 * de is_null y retorna literal true o false.
	 * 
	 * @param Object
	 * @return String
	 */
	private function getBoolColumn($value){
		if($value == 'NO'){
			return "false";
		}else{
			return "true";
		}
	}

	/**
	 * Método que retorna un string como campo,
	 * dependiendo de la opción ingresada como parámetro
	 * dará el permiso:
	 * 1 = public
	 * 2 = private
	 * 3 = protected
	 * 
	 * @param Integer $option
	 * @param String $field
	 */
	private function generateField($option, $field){
		$permiso = "";
		
		switch ($option) {
			case 1:
				$permiso = "public";
				break;
			case 2:
				$permiso = "private";
				break;
			case 1:
				$permiso = "protected";
				break;
			default:
				$permiso = "var";
				break;
		}
		
		return "\t".$permiso." \$".NameUtils::formalObjectName($field).";\n";
	}
		
}

// Main Script
$a = new GenerateEntities();
$a->start();


?>